<!--  
swiper轮播专用canvas批改组件
组件使用说明：
1. props: 
   - imgurl: 图片地址（网络或本地）
   - list: 批改数据数组
   - swiperIndex: 轮播索引，用于区分不同的canvas实例
2. events:
   - @updateList: 当用户手动纠错或删除标注时触发，返回更新后的list数据
   
使用示例：
<canvastest-swiper 
  :imgurl="imageUrl" 
  :list="correctList" 
  :swiperIndex="index"
  @updateList="handleListUpdate"
></canvastest-swiper>
-->
<template>
	<view class="container">
		<canvas :canvas-id="`myCanvas${swiperIndex}`" :id="`myCanvas${swiperIndex}`" type="2d"
			@touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd"
			:style="canvasStyle"></canvas>

		<!-- 编辑弹出层 -->
		<u-popup v-model="showEditDialog" border-radius="16" mode="center">
			<view style="width: 550rpx;padding: 40rpx;">
				<view style="text-align: center;font-size: 36rpx;font-weight: 600;margin-bottom: 30rpx;">
					修改错别字
				</view>
				<view style="margin-bottom: 20rpx;">
					<text style="color: #666;">原字：</text>
					<text style="color: #333;font-weight: bold;">{{ currentEditChar.zi }}</text>
				</view>
				<view style="margin-bottom: 30rpx;">
					<text style="color: #666;">正确字：</text>
				</view>
				<input type="text" class="inp" v-model="editCorrectText" placeholder="请输入正确的字" />
				<view class="f f-a-c f-j-c">
					<view @click="confirmEdit" class="confirm-btn f f-a-c f-j-c">
						确认修改
					</view>
					<view @click="cancelEdit" class="cancel-btn f f-a-c f-j-c">
						取消
					</view>
				</view>
			</view>
		</u-popup>
	</view>
</template>

<script>
	import {
		getErrorChars,
		getMissingChars,
		getCharCenter,
		isClickInChar,
		convertToCanvasCoord,
		convertToOriginalCoord,
		calculateStyles
	} from "@/utils/correctUtils.js"

	export default {
		props: {
			imgurl: {
				type: String,
				required: true
			},
			list: {
				type: Array,
				required: true,
				default: () => []
			},
			swiperIndex: {
				type: Number,
				required: true,
				default: 0
			}
		},
		data() {
			return {
				canvasNode: null,
				ctx: null,
				dpr: 1,
				// 图片相关
				bgImgPath: '',
				originalImageWidth: 0,
				originalImageHeight: 0,
				canvasWidth: 0,
				canvasHeight: 0,
				canvasDisplayWidth: 0,
				canvasDisplayHeight: 0,
				// 样式配置
				circleSize: 25,
				lineWidth: 4,
				fontSize: 50,
				// 错别字数据
				errorChars: [],
				missingChars: [],
				markedChars: [], // 已标记的字符
				// 交互相关
				touchStartX: 0,
				touchStartY: 0,
				isMoving: false,
				moveThreshold: 10,
				// 编辑相关
				showEditDialog: false,
				currentEditChar: {},
				editCorrectText: ''
			}
		},
		computed: {
			canvasStyle() {
				// 如果有原图尺寸，按比例计算显示尺寸
				if (this.canvasWidth && this.canvasHeight) {
					// 限制最大宽度为750rpx
					const maxWidth = 750
					const scale = Math.min(maxWidth / this.canvasWidth, 1)
					const displayWidth = this.canvasWidth * scale
					const displayHeight = this.canvasHeight * scale

					return `width: ${displayWidth}rpx; height: ${displayHeight}rpx; border: 1px solid #ccc;`
				} else {
					return 'width: 750rpx; height: 1000rpx; border: 1px solid #ccc;'
				}
			}
		},
		watch: {
			imgurl: {
				handler(newVal) {
					if (newVal) {
						this.loadImage()
					}
				},
				immediate: true
			},
			list: {
				handler(newVal) {
					console.log(`Canvas ${this.swiperIndex} - list变化检测:`, {
						hasData: !!newVal,
						length: newVal?.length || 0,
						sampleData: newVal?.slice(0, 2) // 只打印前两项作为样本
					})

					// 详细检查收到的数据格式
					if (newVal && newVal.length > 0) {
						console.log(`Canvas ${this.swiperIndex} - 详细数据格式分析:`)
						newVal.forEach((item, index) => {
							console.log(`  Item ${index}:`, {
								hasChars: item.chars !== undefined,
								charsIsArray: Array.isArray(item.chars),
								charsLength: item.chars?.length || 0,
								// 如果直接是errorJuZis格式
								hasReason: item.reason !== undefined,
								hasCorrect: item.correct !== undefined,
								hasLocations: item.locations !== undefined,
								hasZiEIndex: item.ziEIndex !== undefined,
								hasZiSIndex: item.ziSIndex !== undefined,
								// 完整数据（限制输出避免过多日志）
								itemData: Object.keys(item)
							})

							// 如果有chars数组，检查里面的内容
							if (item.chars && Array.isArray(item.chars)) {
								item.chars.slice(0, 3).forEach((char, charIndex) => {
									console.log(`    Char ${charIndex}:`, {
										hasReason: char.reason !== undefined,
										hasCorrect: char.correct !== undefined,
										hasLocations: char.locations !== undefined,
										hasZiEIndex: char.ziEIndex !== undefined,
										hasZiSIndex: char.ziSIndex !== undefined,
										type: char.type,
										charKeys: Object.keys(char)
									})
								})
							}
						})

						// 如果数据看起来像是直接的errorJuZis格式，给出提示
						const firstItem = newVal[0]
						if (firstItem.reason !== undefined && firstItem.correct !== undefined && firstItem.locations !== undefined) {
							console.log(`Canvas ${this.swiperIndex} - 检测到可能的errorJuZis直接格式，需要转换为chars格式`)
						}

						this.processCorrectData()
					}
				},
				immediate: true,
				deep: true
			}
		},
		onReady() {
			// 延迟执行，确保DOM完全准备好
			setTimeout(() => {
				this.initCanvas()
			}, 200 + this.swiperIndex * 100) // 根据索引错开初始化时间
		},
		methods: {
			/**
			 * 加载网络图片
			 */
			async loadImage() {
				if (!this.imgurl) {
					return
				}

				try {
					let imagePath = this.imgurl

					// 判断是否为网络图片
					if (this.imgurl.startsWith('http')) {
						// 检查网络状态
						const networkInfo = await this.getNetworkType()

						if (networkInfo.networkType === 'none') {
							throw new Error('网络连接不可用')
						}

						// 下载网络图片到本地
						const downloadRes = await this.downloadFile(this.imgurl)
						imagePath = downloadRes.tempFilePath
					}

					// 获取图片信息
					const imageInfo = await this.getImageInfo(imagePath)

					this.bgImgPath = imagePath
					this.originalImageWidth = imageInfo.width
					this.originalImageHeight = imageInfo.height

					// 直接使用原图尺寸作为Canvas尺寸
					this.canvasWidth = imageInfo.width
					this.canvasHeight = imageInfo.height

					// 根据图片大小设置样式参数
					if (this.canvasWidth > 2000) {
						this.lineWidth = 4
						this.circleSize = 60
						this.fontSize = 120
					} else {
						this.lineWidth = 2
						this.circleSize = 25
						this.fontSize = 50
					}

					// 如果canvas已经初始化，直接设置，否则等待初始化完成
					if (this.canvasNode && this.ctx) {
						this.setupCanvas()
					}
				} catch (error) {
					console.error('图片加载失败:', error)

					// 如果canvas已准备好，绘制测试背景
					if (this.canvasNode && this.ctx) {
						this.drawTestBackground()
					}
				}
			},

			/**
			 * 获取网络状态
			 */
			getNetworkType() {
				return new Promise((resolve) => {
					uni.getNetworkType({
						success: resolve,
						fail: () => resolve({
							networkType: 'unknown'
						})
					})
				})
			},

			/**
			 * 下载文件
			 */
			downloadFile(url) {
				return new Promise((resolve, reject) => {
					uni.downloadFile({
						url: url,
						success: (res) => {
							if (res.statusCode === 200) {
								resolve(res)
							} else {
								reject(new Error(`下载失败，状态码: ${res.statusCode}`))
							}
						},
						fail: (error) => {
							reject(error)
						}
					})
				})
			},

			/**
			 * 获取图片信息
			 */
			getImageInfo(src) {
				return new Promise((resolve, reject) => {
					uni.getImageInfo({
						src: src,
						success: resolve,
						fail: reject
					})
				})
			},

			/**
			 * 初始化canvas
			 */
			initCanvas() {
				const query = uni.createSelectorQuery().in(this)
				query.select(`#myCanvas${this.swiperIndex}`)
					.fields({
						node: true,
						size: true
					})
					.exec(res => {
						if (res[0]) {
							this.canvasNode = res[0].node
							this.canvasDisplayWidth = res[0].width
							this.canvasDisplayHeight = res[0].height
							this.ctx = this.canvasNode.getContext('2d')
							this.dpr = uni.getSystemInfoSync().pixelRatio

							console.log(`Canvas ${this.swiperIndex} 初始化成功`, {
								displayWidth: this.canvasDisplayWidth,
								displayHeight: this.canvasDisplayHeight,
								dpr: this.dpr
							})

							// 先绘制测试背景，确保canvas正常工作
							this.drawTestBackground()

							// 如果图片已经加载好，再设置canvas
							if (this.bgImgPath) {
								this.setupCanvas()
							}
						} else {
							console.error(`Canvas ${this.swiperIndex} 初始化失败`)
						}
					})
			},

			/**
			 * 设置canvas
			 */
			setupCanvas() {
				if (!this.canvasNode || !this.ctx) {
					return
				}

				// 设置canvas实际尺寸（考虑DPR）
				this.canvasNode.width = this.canvasWidth * this.dpr
				this.canvasNode.height = this.canvasHeight * this.dpr
				this.ctx.scale(this.dpr, this.dpr)

				if (this.bgImgPath) {
					// 有图片时加载图片
					const img = this.canvasNode.createImage()
					img.src = this.bgImgPath

					img.onload = () => {
						// 先清空Canvas
						this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)

						// 直接1:1绘制图片
						this.ctx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight)

						// 绘制标记
						this.drawMarkers()

						// 绘制Canvas标识
						this.drawCanvasIndicator()
					}

					img.onerror = (error) => {
						// 图片加载失败时绘制测试背景
						this.drawTestBackground()
					}
				} else {
					// 没有图片时绘制测试背景
					this.drawTestBackground()
				}
			},

			/**
			 * 绘制测试背景（用于调试）
			 */
			drawTestBackground() {
				if (!this.ctx) {
					console.error('Canvas context not available')
					return
				}

				// 设置默认canvas尺寸如果还没有图片
				if (!this.canvasWidth || !this.canvasHeight) {
					this.canvasWidth = 750
					this.canvasHeight = 1000
				}

				// 设置canvas实际尺寸（考虑DPR）
				this.canvasNode.width = this.canvasWidth * this.dpr
				this.canvasNode.height = this.canvasHeight * this.dpr
				this.ctx.scale(this.dpr, this.dpr)

				console.log(`Canvas ${this.swiperIndex} 绘制测试背景`, {
					canvasWidth: this.canvasWidth,
					canvasHeight: this.canvasHeight
				})

				// 绘制一个渐变背景用于测试
				const gradient = this.ctx.createLinearGradient(0, 0, this.canvasWidth, this.canvasHeight)
				gradient.addColorStop(0, '#f0f0f0')
				gradient.addColorStop(1, '#e0e0e0')

				this.ctx.fillStyle = gradient
				this.ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight)

				// 绘制一些测试文字
				this.ctx.fillStyle = '#333'
				this.ctx.font = '40px Arial'
				this.ctx.textAlign = 'left'
				this.ctx.textBaseline = 'top'
				this.ctx.fillText(`Canvas测试 ${this.swiperIndex + 1}`, 50, 100)
				this.ctx.fillText('等待图片加载...', 50, 150)

				// 绘制字符的可点击区域（用于调试）
				if (this.list && this.list.length > 0) {
					this.ctx.strokeStyle = '#00ff00'
					this.ctx.lineWidth = 2
					this.ctx.setLineDash([5, 5]) // 虚线

					this.list.forEach(item => {
						if (item.chars && Array.isArray(item.chars)) {
							item.chars.forEach(char => {
								// 适配原格式：从locations中找到当前canvas的位置
								if (char.locations && Array.isArray(char.locations)) {
									const location = char.locations.find(loc => loc.imageIndex === this
										.swiperIndex)
									if (location) {
										// 绘制字符边界框
										this.ctx.strokeRect(location.l, location.t, location.w, location.h)

										// 绘制字符中心点
										this.ctx.fillStyle = '#ff0000'
										const center = {
											x: location.l + location.w / 2,
											y: location.t + location.h / 2
										}
										this.ctx.fillRect(center.x - 2, center.y - 2, 4, 4)

										// 标注字符
										this.ctx.fillStyle = '#000'
										this.ctx.font = '20px Arial'
										this.ctx.fillText(char.zi || '?', location.l, location.t - 5)
									}
								}
							})
						}
					})

					this.ctx.setLineDash([]) // 重置为实线
				}

				// 绘制标记
				this.drawMarkers()

				// 绘制Canvas标识
				this.drawCanvasIndicator()
			},

			/**
			 * 判断是否为标点错误
			 */
			isPunctuationError(char) {
				return char.type && (
					char.type.includes('标点') ||
					char.type === '对话标点缺失' ||
					char.type === '标点使用不当' ||
					char.type.includes('引号') ||
					char.type.includes('句号') ||
					char.type.includes('逗号') ||
					char.type.includes('问号') ||
					char.type.includes('感叹号') ||
					char.type.includes('冒号') ||
					char.type.includes('分号') ||
					char.type.includes('省略号') ||
					char.code && char.code.startsWith('BD') // errorBiaoDians的code都是BD开头
				)
			},

			/**
			 * 判断是否为不雅句子（errorJuZis）
			 */
			isErrorSentence(char) {
				// errorJuZis数据特征：有reason、correct、locations、ziEIndex、ziSIndex
				console.log(`Canvas ${this.swiperIndex} - isErrorSentence判断:`, {
					reason: char.reason,
					correct: char.correct,
					type: char.type,
					code: char.code,
					xiuCi: char.xiuCi,
					shangXi: char.shangXi,
					zi: char.zi,
					ziEIndex: char.ziEIndex,
					ziSIndex: char.ziSIndex,
					locations: char.locations?.length || 0
				})

				// 简化判断逻辑：只要有errorJuZis的核心特征就认为是不雅句子
				const hasErrorJuZisFields = char.reason !== undefined &&
					char.correct !== undefined &&
					char.locations !== undefined &&
					Array.isArray(char.locations) &&
					char.locations.length > 0 &&
					char.ziEIndex !== undefined &&
					char.ziSIndex !== undefined

				// 排除明确的其他类型：
				// 1. 如果有shangXi或xiuCi字段，说明是妙句或修辞句子
				// 2. 如果是标点错误，也要排除
				const notOtherTypes = char.shangXi === undefined && 
					char.xiuCi === undefined && 
					!this.isPunctuationError(char)

				const result = hasErrorJuZisFields && notOtherTypes

				console.log(`Canvas ${this.swiperIndex} - isErrorSentence判断结果:`, {
					hasErrorJuZisFields,
					notOtherTypes,
					finalResult: result,
					判断依据: {
						"有reason": char.reason !== undefined,
						"有correct": char.correct !== undefined,
						"有locations": char.locations !== undefined && Array.isArray(char.locations) && char.locations.length > 0,
						"有ziEIndex": char.ziEIndex !== undefined,
						"有ziSIndex": char.ziSIndex !== undefined,
						"无shangXi": char.shangXi === undefined,
						"无xiuCi": char.xiuCi === undefined,
						"不是标点错误": !this.isPunctuationError(char),
						"isPunctuationError结果": this.isPunctuationError(char)
					}
				})

				return result
			},

			/**
			 * 处理批改数据
			 */
			processCorrectData() {
				if (!this.list || this.list.length === 0) {
					console.log(`Canvas ${this.swiperIndex} - 没有数据需要处理`)
					return
				}

				console.log(`Canvas ${this.swiperIndex} - 开始处理数据，list长度:`, this.list.length)
				console.log(`Canvas ${this.swiperIndex} - 完整list数据:`, JSON.stringify(this.list))

				// 检查数据格式并转换
				let processedList = this.list
				
				// 如果第一个元素直接包含errorJuZis的特征（reason, correct, locations），说明需要转换格式
				if (this.list.length > 0 && this.list[0].reason !== undefined && this.list[0].correct !== undefined && this.list[0].locations !== undefined) {
					console.log(`Canvas ${this.swiperIndex} - 检测到errorJuZis直接格式，进行格式转换`)
					
					// 将errorJuZis格式转换为chars格式
					processedList = [{
						chars: this.list.map(errorJuZi => ({
							...errorJuZi,
							// 确保数据完整性
							reason: errorJuZi.reason,
							correct: errorJuZi.correct,
							locations: errorJuZi.locations,
							ziEIndex: errorJuZi.ziEIndex,
							ziSIndex: errorJuZi.ziSIndex
						}))
					}]
					
					console.log(`Canvas ${this.swiperIndex} - 格式转换完成，转换后数据:`, {
						originalLength: this.list.length,
						convertedLength: processedList[0].chars.length,
						sampleConvertedData: processedList[0].chars.slice(0, 2)
					})
				}

				// 适配原本的errorZis、errorBiaoDians和goodJuZis格式
				this.errorChars = this.getErrorCharsFromOriginalFormat(processedList)
				this.missingChars = [] // 暂时不处理漏写字

				// 重新构建markedChars，包含位置信息
				this.markedChars = []
				let errorJuZisCount = 0 // 统计errorJuZis数量
				let allCharsWithReasonCorrect = [] // 所有包含reason/correct的字符

				processedList.forEach((item, listIndex) => {
					console.log(`Canvas ${this.swiperIndex} - 处理item ${listIndex}:`, item)

					if (item.chars && Array.isArray(item.chars)) {
						item.chars.forEach((char, charIndex) => {
							// 记录所有包含reason/correct的字符，用于调试
							if (char.reason !== undefined || char.correct !== undefined) {
								allCharsWithReasonCorrect.push({
									listIndex,
									charIndex,
									reason: char.reason,
									correct: char.correct,
									type: char.type,
									xiuCi: char.xiuCi,
									shangXi: char.shangXi,
									zi: char.zi,
									ziEIndex: char.ziEIndex,
									ziSIndex: char.ziSIndex,
									isGoodSentence: this.isGoodSentence(char),
									isRhetoricalSentence: this.isRhetoricalSentence(char),
									isErrorSentence: this.isErrorSentence(char),
									fullChar: char // 完整字符数据
								})
							}

							// 特别检查errorJuZis
							if (this.isErrorSentence(char)) {
								errorJuZisCount++
								console.log(
									`Canvas ${this.swiperIndex} - 发现errorJuZis ${errorJuZisCount}:`, {
										listIndex,
										charIndex,
										reason: char.reason,
										correct: char.correct,
										type: char.type,
										xiuCi: char.xiuCi,
										ziEIndex: char.ziEIndex,
										ziSIndex: char.ziSIndex,
										locations: char.locations,
										completeCharData: char
									})
							}

							// 对于原格式的错别字、标点错误、妙句、修辞句子和不雅句子，自动标注
							if (char.type === "错别字" || this.isPunctuationError(char) || this
								.isGoodSentence(char) || this.isRhetoricalSentence(char) || this
								.isErrorSentence(char)) {
								this.markedChars.push({
									...char,
									listIndex,
									charIndex
								})
							}
						})
					}
				})

				// 详细分析所有包含reason/correct的字符
				console.log(`Canvas ${this.swiperIndex} - 所有包含reason/correct的字符分析:`)
				allCharsWithReasonCorrect.forEach((charInfo, index) => {
					console.log(`  字符${index + 1}:`, {
						reason: charInfo.reason,
						correct: charInfo.correct,
						type: charInfo.type,
						xiuCi: charInfo.xiuCi,
						shangXi: charInfo.shangXi,
						zi: charInfo.zi,
						ziEIndex: charInfo.ziEIndex,
						ziSIndex: charInfo.ziSIndex,
						判断结果: {
							isGoodSentence: charInfo.isGoodSentence,
							isRhetoricalSentence: charInfo.isRhetoricalSentence,
							isErrorSentence: charInfo.isErrorSentence
						}
					})
				})

				console.log(`Canvas ${this.swiperIndex} - 发现errorJuZis总数:`, errorJuZisCount)
				console.log(`Canvas ${this.swiperIndex} - markedChars总数:`, this.markedChars.length)
				console.log(`Canvas ${this.swiperIndex} - 不雅句子数量:`, this.markedChars.filter(char => this.isErrorSentence(
					char)).length)
				console.log(`Canvas ${this.swiperIndex} - markedChars详情:`, this.markedChars.map(char => ({
					type: char.type,
					reason: char.reason,
					shangXi: char.shangXi,
					xiuCi: char.xiuCi,
					zi: char.zi,
					isErrorSentence: this.isErrorSentence(char)
				})))

				// 如果canvas已准备好，重新绘制
				if (this.ctx && this.bgImgPath) {
					this.redraw()
				}
			},

			/**
			 * 判断是否为妙句
			 */
			isGoodSentence(char) {
				return char.shangXi !== undefined ||
					(char.type && char.type.includes('妙句'))
			},

			/**
			 * 判断是否为修辞句子
			 */
			isRhetoricalSentence(char) {
				return char.xiuCi !== undefined ||
					(char.type && char.type.includes('修辞'))
			},

			/**
			 * 从原格式中提取错误字符
			 */
			getErrorCharsFromOriginalFormat(list) {
				const errorChars = []
				list.forEach(item => {
					if (item.chars && Array.isArray(item.chars)) {
						item.chars.forEach(char => {
							if (char.type === "错别字" || this.isPunctuationError(char) || this
								.isGoodSentence(char) || this.isRhetoricalSentence(char) || this
								.isErrorSentence(char)) {
								errorChars.push(char)
							}
						})
					}
				})
				return errorChars
			},

			/**
			 * 获取字符中心点（适配原格式）
			 */
			getCharCenterFromOriginalFormat(char, currentImageIndex) {
				// 从locations中找到当前canvas对应的位置信息
				const location = char.locations.find(loc => loc.imageIndex === currentImageIndex)
				if (location) {
					return {
						x: location.l + location.w / 2,
						y: location.t + location.h / 2
					}
				}
				return null
			},

			/**
			 * 检查点击是否在字符区域内（适配原格式）
			 */
			isClickInCharFromOriginalFormat(x, y, char, currentImageIndex, padding = 30) {
				const location = char.locations.find(loc => loc.imageIndex === currentImageIndex)
				if (!location) return false

				const expandedL = location.l - padding
				const expandedT = location.t - padding
				const expandedR = location.l + location.w + padding
				const expandedB = location.t + location.h + padding

				return x >= expandedL && x <= expandedR && y >= expandedT && y <= expandedB
			},

			/**
			 * 绘制标记
			 */
			drawMarkers() {
				if (!this.ctx) return

				// 绘制错别字标记
				this.drawErrorMarkers()

				// 绘制漏写字标记
				this.drawMissingMarkers()

				// 绘制妙句波浪线
				this.drawGoodSentenceMarkers()

				// 绘制修辞句子波浪线
				this.drawRhetoricalSentenceMarkers()

				// 绘制不雅句子波浪线
				this.drawErrorSentenceMarkers()
			},

			/**
			 * 绘制错别字标记
			 */
			drawErrorMarkers() {
				if (!this.markedChars || this.markedChars.length === 0) {
					return
				}

				this.ctx.strokeStyle = '#ff0000'
				this.ctx.fillStyle = '#ff0000'
				this.ctx.lineWidth = Math.max(1, this.lineWidth + 1)
				this.ctx.font = `bold ${Math.round(this.fontSize * 1.2)}px Arial`

				this.markedChars.forEach((char, index) => {
					// 只有纯妙句和修辞句子（不是错误字符）才跳过圆圈绘制
					const isError = char.type === "错别字" || this.isPunctuationError(char)
					if ((this.isGoodSentence(char) || this.isRhetoricalSentence(char)) && !isError) {
						return
					}

					// 区分错别字和标点错误的绘制逻辑
					if (char.type === "错别字") {
						// 错别字：保持原有逻辑，绘制单个圆圈
						const center = this.getCharCenterFromOriginalFormat(char, this.swiperIndex)
						if (!center) return

						// 使用稍大的圈圈半径，确保更明显 lzl修改
						const enlargedRadius = this.circleSize + 20

						// 绘制红色圆圈
						this.ctx.beginPath()
						this.ctx.arc(center.x, center.y, enlargedRadius, 0, Math.PI * 2)
						this.ctx.stroke()

						// 绘制正确的字lzl修改
						// const correctText = char.correct // 原格式中使用correct字段
						// if (correctText) {
						// 	// 调整文字位置：圈圈上方偏右一点，位置稍微调高一些
						// 	const textX = center.x + enlargedRadius * 1.2
						// 	const textY = center.y - enlargedRadius - 15 // 增加间距
						// 	// 设置文字对齐方式，确保文字居中对齐
						// 	this.ctx.textAlign = 'center'
						// 	this.ctx.textBaseline = 'bottom'

						// 	this.ctx.fillText(correctText, textX, textY)
						// }
					} else if (this.isPunctuationError(char)) {
						// 标点错误：只在首个和最后一个location位置画圈圈
						if (!char.locations || !Array.isArray(char.locations)) {
							return
						}

						const locations = char.locations.filter(loc => loc.imageIndex === this.swiperIndex)

						if (!locations || locations.length === 0) return

						// 使用稍大的圈圈半径，确保更明显 lzl修改
						const enlargedRadius = this.circleSize + 20

						// 绘制首个位置的圆圈
						if (locations.length > 0) {
							const firstLocation = locations[0]
							const firstCenter = {
								x: firstLocation.l + firstLocation.w / 2,
								y: firstLocation.t + firstLocation.h / 2
							}

							this.ctx.beginPath()
							this.ctx.arc(firstCenter.x, firstCenter.y, enlargedRadius, 0, Math.PI * 2)
							this.ctx.stroke()
						}

						// 如果有多个位置，绘制最后一个位置的圆圈
						if (locations.length > 1) {
							const lastLocation = locations[locations.length - 1]
							const lastCenter = {
								x: lastLocation.l + lastLocation.w / 2,
								y: lastLocation.t + lastLocation.h / 2
							}

							this.ctx.beginPath()
							this.ctx.arc(lastCenter.x, lastCenter.y, enlargedRadius, 0, Math.PI * 2)
							this.ctx.stroke()
						}
					}
				})
			},

			/**
			 * 绘制漏写字标记
			 */
			drawMissingMarkers() {
				if (!this.missingChars || this.missingChars.length === 0) return

				this.ctx.strokeStyle = '#ffaa00'
				this.ctx.lineWidth = this.lineWidth

				this.missingChars.forEach(char => {
					const center = getCharCenter(char.wz)

					// 绘制橙色方框
					this.ctx.strokeRect(
						center.x - this.circleSize,
						center.y - this.circleSize,
						this.circleSize * 2,
						this.circleSize * 2
					)
				})
			},

			/**
			 * 绘制妙句波浪线标记
			 */
			drawGoodSentenceMarkers() {
				if (!this.markedChars || this.markedChars.length === 0) {
					return
				}

				// 筛选出妙句
				const goodSentences = this.markedChars.filter(char => this.isGoodSentence(char))

				goodSentences.forEach((goodSentence, index) => {
					// 获取当前canvas对应的所有位置信息
					const locations = goodSentence.locations.filter(loc => loc.imageIndex === this.swiperIndex)

					// 为每个字符位置单独绘制波浪线
					locations.forEach((location, locationIndex) => {
						// 根据每个字符的具体坐标绘制波浪线
						const startX = location.l
						const startY = location.t + location.h + 8 // 字符下方8像素处开始
						const width = location.w

						// 为每个字符绘制波浪线，增大波纹幅度
						this.drawWavyLine(startX, startY, width, 15) // 增大waveHeight到15，让波纹更明显

						// 在第一个字符的右上角绘制圆圈数字
						if (locationIndex === 0) {
							this.drawGoodSentenceNumber(location, index + 1)
						}
					})
				})
			},

			/**
			 * 绘制妙句序号
			 * @param {Object} location 第一个字符的位置信息
			 * @param {Number} number 序号
			 */
			drawGoodSentenceNumber(location, number) {
				// 数字显示在第一个字符的左上角
				const textX = location.l // 字符左边界X坐标
				const textY = location.t - 5 // 字符上方5像素

				// 绘制红色数字
				this.ctx.fillStyle = '#ff0000'
				this.ctx.font = `bold ${Math.round(this.fontSize * 1.5)}px Arial`
				this.ctx.textAlign = 'left' // 左对齐，确保数字在左上角
				this.ctx.textBaseline = 'bottom'
				this.ctx.fillText(number.toString(), textX, textY)
			},

			/**
			 * 绘制波浪线（参考canvas.vue的实现）
			 * @param {number} x1 起始x坐标
			 * @param {number} y1 起始y坐标
			 * @param {number} width 宽度
			 * @param {number} waveHeight 波浪幅度
			 */
			drawWavyLine(x1, y1, width, waveHeight = 10) {
				const x2 = x1 + width
				const y2 = y1
				const waveCount = Math.max(2, Math.floor(width / 50)) // 根据宽度动态计算波浪数量

				const dx = (x2 - x1) / waveCount
				const dy = (y2 - y1) / waveCount
				let currentX = x1
				let currentY = y1

				this.ctx.beginPath()
				this.ctx.moveTo(x1, y1)

				for (let i = 0; i < waveCount; i++) {
					const cx = currentX + dx / 2
					const cy = currentY + dy / 2 + (i % 2 === 0 ? -waveHeight : waveHeight)
					const nextX = currentX + dx
					const nextY = currentY + dy
					this.ctx.quadraticCurveTo(cx, cy, nextX, nextY)
					currentX = nextX
					currentY = nextY
				}

				this.ctx.strokeStyle = '#ff0000'
				this.ctx.lineWidth = Math.max(3, this.lineWidth)
				this.ctx.stroke()
			},

			/**
			 * 绘制修辞句子波浪线标记
			 */
			drawRhetoricalSentenceMarkers() {
				if (!this.markedChars || this.markedChars.length === 0) {
					return
				}

				// 筛选出修辞句子
				const rhetoricalSentences = this.markedChars.filter(char => this.isRhetoricalSentence(char))

				rhetoricalSentences.forEach((rhetoricalSentence, index) => {
					// 获取当前canvas对应的所有位置信息
					const locations = rhetoricalSentence.locations.filter(loc => loc.imageIndex === this
						.swiperIndex)

					// 为每个字符位置单独绘制波浪线
					locations.forEach((location, locationIndex) => {
						// 根据每个字符的具体坐标绘制波浪线
						const startX = location.l
						const startY = location.t + location.h + 8 // 字符下方8像素处开始
						const width = location.w

						// 为每个字符绘制紫色波浪线，增大波纹幅度
						this.drawRhetoricalWavyLine(startX, startY, width, 15) // 增大waveHeight到15，让波纹更明显

						// 在第一个字符的右上角绘制圆圈数字
						if (locationIndex === 0) {
							this.drawRhetoricalSentenceNumber(location, index + 1)
						}
					})
				})
			},

			/**
			 * 绘制修辞句子序号
			 * @param {Object} location 第一个字符的位置信息
			 * @param {Number} number 序号
			 */
			drawRhetoricalSentenceNumber(location, number) {
				// 数字显示在第一个字符的上方中央
				const textX = location.l + location.w / 2 // 字符中心X坐标
				const textY = location.t - 10 // 字符上方10像素

				// 绘制紫色数字
				this.ctx.fillStyle = '#58c5a2' // 紫色
				this.ctx.font = `bold ${Math.round(this.fontSize * 1.5)}px Arial`
				this.ctx.textAlign = 'center'
				this.ctx.textBaseline = 'bottom'
				this.ctx.fillText(number.toString(), textX, textY)
			},

			/**
			 * 绘制修辞句子专用的紫色波浪线
			 * @param {number} x1 起始x坐标
			 * @param {number} y1 起始y坐标
			 * @param {number} width 宽度
			 * @param {number} waveHeight 波浪幅度
			 */
			drawRhetoricalWavyLine(x1, y1, width, waveHeight = 10) {
				const x2 = x1 + width
				const y2 = y1
				const waveCount = Math.max(2, Math.floor(width / 50)) // 根据宽度动态计算波浪数量

				const dx = (x2 - x1) / waveCount
				const dy = (y2 - y1) / waveCount
				let currentX = x1
				let currentY = y1

				this.ctx.beginPath()
				this.ctx.moveTo(x1, y1)

				for (let i = 0; i < waveCount; i++) {
					const cx = currentX + dx / 2
					const cy = currentY + dy / 2 + (i % 2 === 0 ? -waveHeight : waveHeight)
					const nextX = currentX + dx
					const nextY = currentY + dy
					this.ctx.quadraticCurveTo(cx, cy, nextX, nextY)
					currentX = nextX
					currentY = nextY
				}

				// 使用紫色绘制波浪线
				this.ctx.strokeStyle = '#800080' // 紫色
				this.ctx.lineWidth = Math.max(3, this.lineWidth)
				this.ctx.stroke()
			},

			/**
			 * 绘制不雅句子波浪线标记
			 */
			drawErrorSentenceMarkers() {
				if (!this.markedChars || this.markedChars.length === 0) {
					console.log(`Canvas ${this.swiperIndex} - 没有markedChars，跳过不雅句子绘制`)
					return
				}

				// 筛选出不雅句子
				const errorSentences = this.markedChars.filter(char => this.isErrorSentence(char))

				console.log(`Canvas ${this.swiperIndex} - 开始绘制不雅句子，总数:`, errorSentences.length)

				// 根据reason和correct字段去重，避免重复绘制
				const uniqueErrorSentences = []
				const seenSentences = new Set()

				errorSentences.forEach((errorSentence) => {
					// 使用reason+correct作为唯一标识
					const uniqueKey = `${errorSentence.reason}_${errorSentence.correct}`
					if (!seenSentences.has(uniqueKey)) {
						seenSentences.add(uniqueKey)
						uniqueErrorSentences.push(errorSentence)
						console.log(`Canvas ${this.swiperIndex} - 添加唯一不雅句子:`, {
							reason: errorSentence.reason,
							correct: errorSentence.correct,
							uniqueKey: uniqueKey
						})
					} else {
						console.log(`Canvas ${this.swiperIndex} - 跳过重复不雅句子:`, {
							reason: errorSentence.reason,
							correct: errorSentence.correct,
							uniqueKey: uniqueKey
						})
					}
				})

				console.log(`Canvas ${this.swiperIndex} - 去重后不雅句子数量:`, uniqueErrorSentences.length)

				uniqueErrorSentences.forEach((errorSentence, sentenceIndex) => {
					console.log(`Canvas ${this.swiperIndex} - 绘制不雅句子 ${sentenceIndex + 1}:`, {
						reason: errorSentence.reason,
						correct: errorSentence.correct,
						totalLocations: errorSentence.locations?.length || 0
					})

					// 确保locations存在且为数组
					if (!errorSentence.locations || !Array.isArray(errorSentence.locations)) {
						console.warn(`Canvas ${this.swiperIndex} - 不雅句子 ${sentenceIndex + 1} 缺少locations数据`)
						return
					}

					// 获取当前canvas对应的所有位置信息
					const locations = errorSentence.locations.filter(loc => loc.imageIndex === this.swiperIndex)

					console.log(`Canvas ${this.swiperIndex} - 不雅句子 ${sentenceIndex + 1} 在当前canvas的位置数量:`, locations
						.length)

					if (locations.length === 0) {
						console.log(`Canvas ${this.swiperIndex} - 不雅句子 ${sentenceIndex + 1} 在当前canvas无位置信息`)
						return
					}

					// 为每个字符位置单独绘制蓝色波浪线
					locations.forEach((location, locationIndex) => {
						console.log(
							`Canvas ${this.swiperIndex} - 绘制位置 ${locationIndex + 1}/${locations.length}:`, {
								l: location.l,
								t: location.t,
								w: location.w,
								h: location.h,
								imageIndex: location.imageIndex
							})

						// 根据每个字符的具体坐标绘制波浪线
						const startX = location.l
						const startY = location.t + location.h + 8 // 字符下方8像素处开始
						const width = location.w

						// 为每个字符绘制蓝色波浪线，增大波纹幅度
						this.drawErrorSentenceWavyLine(startX, startY, width, 15) // 增大waveHeight到15，让波纹更明显

						// 在第一个字符的上方绘制序号
						if (locationIndex === 0) {
							this.drawErrorSentenceNumber(location, sentenceIndex + 1)
						}
					})

					console.log(
						`Canvas ${this.swiperIndex} - 完成绘制不雅句子 ${sentenceIndex + 1}，共绘制 ${locations.length} 个位置`
					)
				})

				console.log(`Canvas ${this.swiperIndex} - 完成所有不雅句子绘制`)
			},

			/**
			 * 绘制不雅句子序号
			 * @param {Object} location 第一个字符的位置信息
			 * @param {Number} number 序号
			 */
			drawErrorSentenceNumber(location, number) {
				// 数字显示在第一个字符的左上角（而不是上方中央）
				const textX = location.l // 字符左边界X坐标
				const textY = location.t - 5 // 字符上方5像素

				// 绘制蓝色数字
				this.ctx.fillStyle = '#1E90FF' // 蓝色
				this.ctx.font = `bold ${Math.round(this.fontSize * 1.5)}px Arial`
				this.ctx.textAlign = 'left' // 左对齐，确保数字在左上角
				this.ctx.textBaseline = 'bottom'
				this.ctx.fillText(number.toString(), textX, textY)
			},

			/**
			 * 绘制不雅句子专用的蓝色波浪线
			 * @param {number} x1 起始x坐标
			 * @param {number} y1 起始y坐标
			 * @param {number} width 宽度
			 * @param {number} waveHeight 波浪幅度
			 */
			drawErrorSentenceWavyLine(x1, y1, width, waveHeight = 10) {
				console.log(`Canvas ${this.swiperIndex} - 正在绘制蓝色波浪线:`, {
					x1,
					y1,
					width,
					waveHeight
				})

				const x2 = x1 + width
				const y2 = y1
				const waveCount = Math.max(2, Math.floor(width / 50)) // 根据宽度动态计算波浪数量

				const dx = (x2 - x1) / waveCount
				const dy = (y2 - y1) / waveCount
				let currentX = x1
				let currentY = y1

				this.ctx.beginPath()
				this.ctx.moveTo(x1, y1)

				for (let i = 0; i < waveCount; i++) {
					const cx = currentX + dx / 2
					const cy = currentY + dy / 2 + (i % 2 === 0 ? -waveHeight : waveHeight)
					const nextX = currentX + dx
					const nextY = currentY + dy
					this.ctx.quadraticCurveTo(cx, cy, nextX, nextY)
					currentX = nextX
					currentY = nextY
				}

				// 使用蓝色绘制波浪线
				this.ctx.strokeStyle = '#1E90FF' // 蓝色
				this.ctx.lineWidth = Math.max(5, this.lineWidth) // 加粗线条，便于观察
				this.ctx.stroke()

				console.log(`Canvas ${this.swiperIndex} - 蓝色波浪线绘制完成，颜色: #1E90FF, 线宽: ${Math.max(5, this.lineWidth)}`)
			},

			/**
			 * 处理触摸开始
			 */
			handleTouchStart(e) {
				const touch = e.touches[0]
				const canvasCoord = this.convertDisplayToCanvas(touch.x, touch.y)

				this.touchStartX = canvasCoord.x
				this.touchStartY = canvasCoord.y
				this.isMoving = false
			},

			/**
			 * 处理触摸移动
			 */
			handleTouchMove(e) {
				const touch = e.touches[0]
				const canvasCoord = this.convertDisplayToCanvas(touch.x, touch.y)

				const dx = Math.abs(canvasCoord.x - this.touchStartX)
				const dy = Math.abs(canvasCoord.y - this.touchStartY)

				if (dx > this.moveThreshold || dy > this.moveThreshold) {
					this.isMoving = true
				}
			},

			/**
			 * 处理触摸结束
			 */
			handleTouchEnd(e) {
				if (!this.isMoving) {
					// 这是一次点击
					this.handleClick(this.touchStartX, this.touchStartY)
				}
			},

			/**
			 * 处理点击事件
			 */
			handleClick(x, y) {
				// 遍历所有list中的字符，检测是否点击了带有locations信息的字符
				for (let listIndex = 0; listIndex < this.list.length; listIndex++) {
					const item = this.list[listIndex]
					if (!item.chars || !Array.isArray(item.chars)) continue

					for (let charIndex = 0; charIndex < item.chars.length; charIndex++) {
						const char = item.chars[charIndex]

						// 只检测带有locations信息的字符（原格式）
						if (!char.locations || !Array.isArray(char.locations) || char.locations.length === 0) {
							continue
						}

						// 增大点击检测范围，使用更大的padding
						const padding = Math.max(this.circleSize, 30) // 至少30像素的点击范围
						if (this.isClickInCharFromOriginalFormat(x, y, char, this.swiperIndex, padding)) {
							// 检查这个字符是否已经被标注
							const isMarked = this.isCharMarked(listIndex, charIndex)

							if (isMarked) {
								// 如果已经标注，则删除标注
								this.removeCharMark(listIndex, charIndex)
								uni.showToast({
									title: '已删除标注',
									icon: 'success'
								})
							} else {
								// 如果未标注，则弹出编辑弹窗
								this.showEditForChar(listIndex, charIndex)
							}
							return
						}
					}
				}
			},

			/**
			 * 检查字符是否已被标注
			 */
			isCharMarked(listIndex, charIndex) {
				const char = this.list[listIndex].chars[charIndex]
				return char.type === "错别字" || this.isPunctuationError(char) || this.isGoodSentence(char) || this
					.isRhetoricalSentence(char) || this.isErrorSentence(char) || (char
						.isMarked === true)
			},

			/**
			 * 删除字符标注
			 */
			removeCharMark(listIndex, charIndex) {
				// 从原始list中删除标注信息
				const char = this.list[listIndex].chars[charIndex]

				// 删除标记：清除标注信息，保持原本类型
				this.$set(char, 'isMarked', false)

				// 从markedChars中移除
				this.markedChars = this.markedChars.filter(markedChar => {
					return !(markedChar.listIndex === listIndex && markedChar.charIndex === charIndex)
				})

				// 通过$emit将更新后的list同步到父组件
				const cleanedList = this.getCleanedList()
				this.$emit('updateList', cleanedList, this.swiperIndex)

				// 重新绘制
				this.redraw()
			},

			/**
			 * 显示字符编辑弹窗
			 */
			showEditForChar(listIndex, charIndex) {
				const char = this.list[listIndex].chars[charIndex]

				this.showEditDialog = true
				this.currentEditChar = {
					...char,
					listIndex,
					charIndex
				}
				this.editCorrectText = char.correct || '' // 使用correct字段
			},

			/**
			 * 清理list数据，去掉isMarked参数
			 */
			getCleanedList() {
				const cleanedList = JSON.parse(JSON.stringify(this.list))
				cleanedList.forEach(item => {
					if (item.chars && Array.isArray(item.chars)) {
						item.chars.forEach(char => {
							delete char.isMarked
						})
					}
				})
				return cleanedList
			},

			/**
			 * 转换显示坐标到canvas坐标
			 */
			convertDisplayToCanvas(displayX, displayY) {
				if (!this.canvasDisplayWidth || !this.canvasDisplayHeight || !this.canvasWidth || !this.canvasHeight) {
					return {
						x: displayX,
						y: displayY
					}
				}

				const realX = displayX / this.canvasDisplayWidth * this.canvasWidth
				const realY = displayY / this.canvasDisplayHeight * this.canvasHeight

				return {
					x: realX,
					y: realY
				}
			},

			/**
			 * 确认编辑
			 */
			confirmEdit() {
				if (!this.editCorrectText.trim()) {
					uni.showToast({
						title: '请输入正确的字',
						icon: 'none'
					})
					return
				}

				const {
					listIndex,
					charIndex
				} = this.currentEditChar

				// 更新原始list数组中的数据
				const char = this.list[listIndex].chars[charIndex]
				this.$set(char, 'correct', this.editCorrectText.trim()) // 使用correct字段
				this.$set(char, 'isMarked', true)
				this.$set(char, 'type', "错别字") // 设置为错别字类型

				// 检查是否已经在markedChars中，如果不在则添加
				const existingIndex = this.markedChars.findIndex(markedChar =>
					markedChar.listIndex === listIndex && markedChar.charIndex === charIndex
				)

				if (existingIndex === -1) {
					this.markedChars.push({
						...char,
						listIndex,
						charIndex
					})
				} else {
					this.markedChars[existingIndex] = {
						...char,
						listIndex,
						charIndex
					}
				}

				// 通过$emit将更新后的list同步到父组件
				const cleanedList = this.getCleanedList()
				this.$emit('updateList', cleanedList, this.swiperIndex)

				// 重新绘制
				this.redraw()

				// 关闭弹出层
				this.cancelEdit()

				uni.showToast({
					title: '修改成功',
					icon: 'success'
				})
			},

			/**
			 * 取消编辑
			 */
			cancelEdit() {
				this.showEditDialog = false
				this.currentEditChar = {}
				this.editCorrectText = ''
			},

			/**
			 * 重新绘制
			 */
			redraw() {
				if (!this.ctx || !this.bgImgPath) return

				// 清除canvas
				this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)

				// 重新绘制背景图片
				const img = this.canvasNode.createImage()
				img.src = this.bgImgPath

				img.onload = () => {
					this.ctx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight)
					this.drawMarkers()

					// 绘制Canvas标识
					this.drawCanvasIndicator()
				}
			},

			/**
			 * 绘制Canvas标识
			 */
			drawCanvasIndicator() {
				if (!this.ctx) return

				const text = `第${this.swiperIndex + 1}张`
				const padding = 20
				const fontSize = 36

				// 设置字体样式
				this.ctx.font = `bold ${fontSize}px Arial`
				this.ctx.textAlign = 'left'
				this.ctx.textBaseline = 'top'

				// 绘制红色文字
				this.ctx.fillStyle = '#ff0000'
				this.ctx.fillText(text, padding, padding)
			}
		},

		beforeDestroy() {
			// 清理资源
			if (this.canvasNode) {
				this.canvasNode = null
				this.ctx = null
			}
		}
	}
</script>

<style>
	.container {
		position: relative;
		/* padding: 20rpx; */
	}

	.confirm-btn {
		width: 180rpx;
		height: 70rpx;
		background: #05C490;
		border-radius: 20rpx;
		font-size: 28rpx;
		color: #FFFFFF;
		margin-right: 20rpx;
	}

	.cancel-btn {
		width: 180rpx;
		height: 70rpx;
		background: #cccccc;
		border-radius: 20rpx;
		font-size: 28rpx;
		color: #666666;
	}

	.inp {
		border-radius: 20rpx;
		border: 2rpx solid #CCCCCC;
		color: #000;
		padding-left: 20rpx;
		height: 70rpx;
		width: 100%;
		margin-bottom: 30rpx;
	}

	.inp::placeholder {
		color: #CCCCCC;
	}

	.f {
		display: flex;
	}

	.f-a-c {
		align-items: center;
	}

	.f-j-c {
		justify-content: center;
	}
</style>